import { arrayMethods } from "./array";
import { defineProperty } from "../../util";

/**
 * 数据观测类
 * 使用defineProperty 重新定义属性
 */
class Observer {
    constructor(value) {
        // 判断一个对象是否被观测过，看他有没有__ob__这个属性
        // Object.defineProperty(value, '__ob__', {
        //     enumerable: false, // 不能被枚举，不能被循环出来
        //     configurable: false,
        //     value: this
        // })
        defineProperty(value, '__ob__', this)


        if (Array.isArray(value)) {
            // 数组处理：函数劫持、切片编程思想，重写push shift pop unshift splice sort reverse
            value.__proto__ = arrayMethods;
            // 观测数组中的对象类型
            this.observeArray(value);
        } else {
            // 对象处理
            this.walk(value);
        }
    }
    observeArray(value) {
        // 遍历数组的每一项进行观测
        value.forEach(item => {
            observe(item);
        })
    }
    walk(data) {
        // 获取对象的key
        let keys = Object.keys(data);
        keys.forEach(key => {
            defineReactive(data, key, data[key]); // >Vue.util.defineReactive
        })
    }
}

function defineReactive(data, key, value) {
    // 如果值是对象进行递归观测
    observe(value);

    Object.defineProperty(data, key, {
        get() {
            console.log('取值');
            return value
        },
        set(newValue) {
            console.log('设值');
            if (newValue == value) return;
            // 如果用户设值的值是对象，需要再次进行递归观测
            observe(newValue);

            value = newValue;
        }
    })
}


/**
 * 数据观测
 * @param {} data 
 */
export function observe(data) {
    // 对象数据校验：不是对象 或 null 就返回
    if (typeof data !== 'object' || data === null) {
        return data
    }
    // 如果数据被观测过，直接返回，防止重复观测
    if (data.__ob__) {
        return data
    }

    // 数据观测
    new Observer(data);
}